﻿#region 命名空间
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;
using Microsoft.Xna.Framework.Content.Pipeline;
using MonoGameContentProcessors;
using MonoGameContentBuild;
#endregion

namespace ContentFactory
{
    /// <summary>
    /// 素材生成器。
    /// </summary>
    public sealed class ContentBuilder : ContentObject
    {
        #region 字段

        static readonly Dictionary<string, FileSystemWatcher> watchers;

        FileSystemWatcher _watcher;

        #endregion

        #region 属性

        /// <summary>
        /// 素材的本地文件路径。
        /// </summary>
        public string FileName
        {
            get { return _fileName; }
            set
            {
                if (_fileName != value)
                {
                    _fileName = value;
                    this.Raise("FileName");

                    Icon = IconManager.GetFileIcon(_fileName);
                    if (_watcher != null)
                    {
                        _watcher.Changed -= this.FileSystemChanged;
                    }
                    _watcher = GetWatcher(_fileName);
                    _watcher.Changed += this.FileSystemChanged;
                }
            }
        }
        string _fileName;

        /// <summary>
        /// 素材导入程序的特性。
        /// </summary>
        [XmlIgnore]
        public ContentImporterAttribute ImporterAttribute
        {
            get { return _importerAttribute; }
            set
            {
                if (_importerAttribute != value)
                {
                    _importerAttribute = value;
                    this.Raise("ImporterAttribute");

                    Importer = PipelineManager.CreateImporter(_importerAttribute);
                }
            }
        }
        ContentImporterAttribute _importerAttribute;

        /// <summary>
        /// 素材处理程序的特性。
        /// </summary>
        [XmlIgnore]
        public ContentProcessorAttribute ProcessorAttribute
        {
            get { return _processorAttribute; }
            set
            {
                if (_processorAttribute != value)
                {
                    _processorAttribute = value;
                    this.Raise("ProcessorAttribute");

                    Processor = PipelineManager.CreateProcessor(_processorAttribute);
                }
            }
        }
        ContentProcessorAttribute _processorAttribute;

        /// <summary>
        /// 用于序列化的素材导入程序。
        /// </summary>
        public object ImporterObject
        {
            get { return _importer; }
            set { _importer = value as IContentImporter; }
        }

        /// <summary>
        /// 素材导入程序的实例。
        /// </summary>
        [XmlIgnore]
        public IContentImporter Importer
        {
            get { return _importer; }
            set
            {
                if (_importer != value)
                {
                    _importer = value;
                    this.Raise("Importer");
                }
            }
        }
        IContentImporter _importer;

        /// <summary>
        /// 用于序列化的素材处理程序。
        /// </summary>
        public object ProcessorObject
        {
            get { return _processor; }
            set { _processor = value as IContentProcessor; }
        }

        /// <summary>
        /// 素材处理程序的实例。
        /// </summary>
        [XmlIgnore]
        public IContentProcessor Processor
        {
            get { return _processor; }
            set
            {
                if (_processor != value)
                {
                    _processor = value;
                    this.Raise("Processor");
                }
            }
        }
        IContentProcessor _processor;

        /// <summary>
        /// 是否压缩素材。
        /// </summary>
        public bool CompressContent
        {
            get { return _compressContent; }
            set
            {
                if (_compressContent != value)
                {
                    _compressContent = value;
                    this.Raise("CompressContent");
                }
            }
        }
        bool _compressContent;

        #region 素材状态

        /// <summary>
        /// Windows 平台素材的状态。
        /// </summary>
        public ContentState WindowsContentState
        {
            get { return _windowsContentState; }
            set
            {
                if (_windowsContentState != value)
                {
                    _windowsContentState = value;
                    this.Raise("WindowsContentState");
                }
            }
        }
        ContentState _windowsContentState;

        /// <summary>
        /// Windows8 平台素材的状态。
        /// </summary>
        public ContentState Windows8ContentState
        {
            get { return _windows8ContentState; }
            set
            {
                if (_windows8ContentState != value)
                {
                    _windows8ContentState = value;
                    this.Raise("Windows8ContentState");
                }
            }
        }
        ContentState _windows8ContentState;

        /// <summary>
        /// iOS 平台素材的状态。
        /// </summary>
        public ContentState iOSContentState
        {
            get { return _iOSContentState; }
            set
            {
                if (_iOSContentState != value)
                {
                    _iOSContentState = value;
                    this.Raise("iOSContentState");
                }
            }
        }
        ContentState _iOSContentState;

        /// <summary>
        /// Android 平台素材的状态。
        /// </summary>
        public ContentState AndroidContentState
        {
            get { return _androidContentState; }
            set
            {
                if (_androidContentState != value)
                {
                    _androidContentState = value;
                    this.Raise("AndroidContentState");
                }
            }
        }
        ContentState _androidContentState;

        /// <summary>
        /// Linux 平台素材的状态。
        /// </summary>
        public ContentState LinuxContentState
        {
            get { return _linuxContentState; }
            set
            {
                if (_linuxContentState != value)
                {
                    _linuxContentState = value;
                    this.Raise("LinuxContentState");
                }
            }
        }
        ContentState _linuxContentState;

        /// <summary>
        /// OSX 平台素材的状态。
        /// </summary>
        public ContentState OSXContentState
        {
            get { return _oSXContentState; }
            set
            {
                if (_oSXContentState != value)
                {
                    _oSXContentState = value;
                    this.Raise("OSXContentState");
                }
            }
        }
        ContentState _oSXContentState;

        /// <summary>
        /// PSM 平台素材的状态。
        /// </summary>
        public ContentState PSMContentState
        {
            get { return _pSMContentState; }
            set
            {
                if (_pSMContentState != value)
                {
                    _pSMContentState = value;
                    this.Raise("PSMContentState");
                }
            }
        }
        ContentState _pSMContentState;

        #endregion

        #endregion

        #region 初始化

        /// <summary>
        /// 初始化。
        /// </summary>
        static ContentBuilder()
        {
            watchers = new Dictionary<string, FileSystemWatcher>();
        }

        #endregion

        #region 方法

        // 获取文件监视器。
        static FileSystemWatcher GetWatcher(string fileName)
        {
            string directory = Path.GetDirectoryName(fileName);
            if (!watchers.ContainsKey(directory))
            {
                FileSystemWatcher watcher = new FileSystemWatcher(directory);
                watcher.EnableRaisingEvents = true;
                watchers.Add(directory, watcher);
            }
            return watchers[directory];
        }

        /// <summary>
        /// 生成指定平台的素材。
        /// </summary>
        public void Build(string output, MonoGamePlatform targetPlatform, ContentBuildCallback completed)
        {
            ContentBuildSystem.Build(_fileName,
                output,
                _importer,
                _processor,
                targetPlatform,
                _compressContent,
                completed);
        }

        /// <summary>
        /// 设置素材状态。
        /// </summary>
        public void SetState(MonoGamePlatform targetPlatform, ContentState state)
        {
            switch (targetPlatform)
            {
                case MonoGamePlatform.Windows:
                    WindowsContentState = state;
                    break;
                case MonoGamePlatform.Windows8:
                    Windows8ContentState = state;
                    break;
                case MonoGamePlatform.iOS:
                    iOSContentState = state;
                    break;
                case MonoGamePlatform.Android:
                    AndroidContentState = state;
                    break;
                case MonoGamePlatform.Linux:
                    LinuxContentState = state;
                    break;
                case MonoGamePlatform.OSX:
                    OSXContentState = state;
                    break;
                case MonoGamePlatform.PSM:
                    PSMContentState = state;
                    break;
                default:
                    break;
            }
        }

        /// <summary>
        /// 清除素材所有平台的状态。
        /// </summary>
        public void ClearState()
        {
            WindowsContentState = ContentState.UnCreated;
            Windows8ContentState = ContentState.UnCreated;
            iOSContentState = ContentState.UnCreated;
            AndroidContentState = ContentState.UnCreated;
            LinuxContentState = ContentState.UnCreated;
            OSXContentState = ContentState.UnCreated;
            PSMContentState = ContentState.UnCreated;
        }

        /// <summary>
        /// 获取素材状态。
        /// </summary>
        public ContentState GetState(MonoGamePlatform targetPlatform)
        {
            switch (targetPlatform)
            {
                case MonoGamePlatform.Windows:
                    return WindowsContentState;
                case MonoGamePlatform.Windows8:
                    return Windows8ContentState;
                case MonoGamePlatform.iOS:
                    return iOSContentState;
                case MonoGamePlatform.Android:
                    return AndroidContentState;
                case MonoGamePlatform.Linux:
                    return LinuxContentState;
                case MonoGamePlatform.OSX:
                    return OSXContentState;
                case MonoGamePlatform.PSM:
                    return PSMContentState;
                default:
                    return ContentState.Created;
            }
        }

        /// <summary>
        /// 序列化时设置导入/处理程序的特性。
        /// </summary>
        internal void SetAttributes(ContentImporterAttribute importerAttribute, ContentProcessorAttribute processorAttribute)
        {
            _importerAttribute = importerAttribute;
            _processorAttribute = processorAttribute;
        }

        #endregion

        #region 事件处理

        // 当文件系统更改时调用。
        void FileSystemChanged(object sender, FileSystemEventArgs e)
        {
            if (e.FullPath == _fileName)
            {
                this.ClearState();
            }
        }

        #endregion
    }
}
